3 use Wikimedia\Rdbms\IDatabase
;
4 use Wikimedia\Rdbms\DatabasePostgres
;
5 use Wikimedia\ScopedCallback
;
6 use Wikimedia\TestingAccessWrapper
;
11 class DatabasePostgresTest
extends MediaWikiTestCase
{
13 private function doTestInsertIgnore() {
15 $reset = new ScopedCallback( function () use ( $fname ) {
16 if ( $this->db
->explicitTrxActive() ) {
17 $this->db
->rollback( $fname );
19 $this->db
->query( 'DROP TABLE IF EXISTS ' . $this->db
->tableName( 'foo' ), $fname );
23 "CREATE TEMPORARY TABLE {$this->db->tableName( 'foo' )} (i INTEGER NOT NULL PRIMARY KEY)",
26 $this->db
->insert( 'foo', [ [ 'i' => 1 ], [ 'i' => 2 ] ], __METHOD__
);
28 // Normal INSERT IGNORE
29 $this->db
->begin( __METHOD__
);
31 'foo', [ [ 'i' => 3 ], [ 'i' => 2 ], [ 'i' => 5 ] ], __METHOD__
, [ 'IGNORE' ]
33 $this->assertSame( 2, $this->db
->affectedRows() );
35 [ '1', '2', '3', '5' ],
36 $this->db
->selectFieldValues( 'foo', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
38 $this->db
->rollback( __METHOD__
);
40 // INSERT IGNORE doesn't ignore stuff like NOT NULL violations
41 $this->db
->begin( __METHOD__
);
42 $this->db
->startAtomic( __METHOD__
, IDatabase
::ATOMIC_CANCELABLE
);
45 'foo', [ [ 'i' => 7 ], [ 'i' => null ] ], __METHOD__
, [ 'IGNORE' ]
47 $this->db
->endAtomic( __METHOD__
);
48 $this->fail( 'Expected exception not thrown' );
49 } catch ( DBQueryError
$e ) {
50 $this->assertSame( 0, $this->db
->affectedRows() );
51 $this->db
->cancelAtomic( __METHOD__
);
55 $this->db
->selectFieldValues( 'foo', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
57 $this->db
->rollback( __METHOD__
);
61 * @covers Wikimedia\Rdbms\DatabasePostgres::insert
63 public function testInsertIgnoreOld() {
64 if ( !$this->db
instanceof DatabasePostgres
) {
65 $this->markTestSkipped( 'Not PostgreSQL' );
67 if ( $this->db
->getServerVersion() < 9.5 ) {
68 $this->doTestInsertIgnore();
70 // Hack version to make it take the old code path
71 $w = TestingAccessWrapper
::newFromObject( $this->db
);
72 $oldVer = $w->numericVersion
;
73 $w->numericVersion
= 9.4;
75 $this->doTestInsertIgnore();
77 $w->numericVersion
= $oldVer;
83 * @covers Wikimedia\Rdbms\DatabasePostgres::insert
85 public function testInsertIgnoreNew() {
86 if ( !$this->db
instanceof DatabasePostgres
) {
87 $this->markTestSkipped( 'Not PostgreSQL' );
89 if ( $this->db
->getServerVersion() < 9.5 ) {
90 $this->markTestSkipped( 'PostgreSQL version is ' . $this->db
->getServerVersion() );
93 $this->doTestInsertIgnore();
96 private function doTestInsertSelectIgnore() {
98 $reset = new ScopedCallback( function () use ( $fname ) {
99 if ( $this->db
->explicitTrxActive() ) {
100 $this->db
->rollback( $fname );
102 $this->db
->query( 'DROP TABLE IF EXISTS ' . $this->db
->tableName( 'foo' ), $fname );
103 $this->db
->query( 'DROP TABLE IF EXISTS ' . $this->db
->tableName( 'bar' ), $fname );
107 "CREATE TEMPORARY TABLE {$this->db->tableName( 'foo' )} (i INTEGER)",
111 "CREATE TEMPORARY TABLE {$this->db->tableName( 'bar' )} (i INTEGER NOT NULL PRIMARY KEY)",
114 $this->db
->insert( 'bar', [ [ 'i' => 1 ], [ 'i' => 2 ] ], __METHOD__
);
116 // Normal INSERT IGNORE
117 $this->db
->begin( __METHOD__
);
118 $this->db
->insert( 'foo', [ [ 'i' => 3 ], [ 'i' => 2 ], [ 'i' => 5 ] ], __METHOD__
);
119 $this->db
->insertSelect( 'bar', 'foo', [ 'i' => 'i' ], [], __METHOD__
, [ 'IGNORE' ] );
120 $this->assertSame( 2, $this->db
->affectedRows() );
122 [ '1', '2', '3', '5' ],
123 $this->db
->selectFieldValues( 'bar', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
125 $this->db
->rollback( __METHOD__
);
127 // INSERT IGNORE doesn't ignore stuff like NOT NULL violations
128 $this->db
->begin( __METHOD__
);
129 $this->db
->insert( 'foo', [ [ 'i' => 7 ], [ 'i' => null ] ], __METHOD__
);
130 $this->db
->startAtomic( __METHOD__
, IDatabase
::ATOMIC_CANCELABLE
);
132 $this->db
->insertSelect( 'bar', 'foo', [ 'i' => 'i' ], [], __METHOD__
, [ 'IGNORE' ] );
133 $this->db
->endAtomic( __METHOD__
);
134 $this->fail( 'Expected exception not thrown' );
135 } catch ( DBQueryError
$e ) {
136 $this->assertSame( 0, $this->db
->affectedRows() );
137 $this->db
->cancelAtomic( __METHOD__
);
141 $this->db
->selectFieldValues( 'bar', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
143 $this->db
->rollback( __METHOD__
);
147 * @covers Wikimedia\Rdbms\DatabasePostgres::nativeInsertSelect
149 public function testInsertSelectIgnoreOld() {
150 if ( !$this->db
instanceof DatabasePostgres
) {
151 $this->markTestSkipped( 'Not PostgreSQL' );
153 if ( $this->db
->getServerVersion() < 9.5 ) {
154 $this->doTestInsertSelectIgnore();
156 // Hack version to make it take the old code path
157 $w = TestingAccessWrapper
::newFromObject( $this->db
);
158 $oldVer = $w->numericVersion
;
159 $w->numericVersion
= 9.4;
161 $this->doTestInsertSelectIgnore();
163 $w->numericVersion
= $oldVer;
169 * @covers Wikimedia\Rdbms\DatabasePostgres::nativeInsertSelect
171 public function testInsertSelectIgnoreNew() {
172 if ( !$this->db
instanceof DatabasePostgres
) {
173 $this->markTestSkipped( 'Not PostgreSQL' );
175 if ( $this->db
->getServerVersion() < 9.5 ) {
176 $this->markTestSkipped( 'PostgreSQL version is ' . $this->db
->getServerVersion() );
179 $this->doTestInsertSelectIgnore();